/*
 * @Author: wuzhouhai wzh200x@126.com
 * @Date: 2024-07-09 11:13:39
 * @LastEditors: wzh200x@126.com
 * @LastEditTime: 2025-08-21 11:33:27
 * @FilePath: \dwys_web\extensions\phoenix-plugin-client\assets\core\PhoenixRoot.ts
 * @Description: 
 */
import { Component, Game, JsonAsset, Node, _decorator, director, game, screen, sys } from "cc";
import PhoenixIns, { Phoenix } from './Phoenix';
import { PhoenixEventDefine } from './defines/event.define';
import { PlatformDefine } from './defines/platform.define';
import { Account } from './entities/Account';
import { Avatar } from './entities/Avatar';
import messageManager from "./managers/message.manager";
import { __private } from "cc";
import { NodeEventType } from "cc";
import { Packet } from "./net/packet/packet";
import { CCString } from "cc";
import { IModelData } from "./interface/iModelData";
import dayjs from 'dayjs';
import { OrderCreateInput } from "./dto/order.create.input.";
import { OrderQueryInput } from "./dto/order.query.input";
import { OrderSendInput } from "./dto/order.sendGoods.input";
import { OrderPayedInput } from "./dto/order.payed.input";
import { AvatarModuleResponse } from "./response/avatar.module.reponse";
import { CardChooseInput } from "./dto/card-choose.input";

const { property } = _decorator;

function PhoenixInit(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
    const originalMethod = descriptor.value;

    descriptor.value = function (...args: any[]) {
        // @ts-ignore
        if (this.phoenix!.CheckIsInit()) {
            return originalMethod.apply(this, args);
        } else {
            console.log(`请先调用InitPhoeix方法初始化Phoenix`);
        }
    };

    return descriptor;
}

export class PhoenixRoot extends Component{
    phoenix: Phoenix|null = null;
    @property({type:[CCString], displayName: '服务器地址', tooltip: '填写IP或是域名' })
    host:string[] = [];

    @property({ displayName: '服务器端口', tooltip: '80或443请留空' })
    port = '';

    @property({ displayName: '请求签名秘钥', tooltip: '找服务器开发获取' })
    secretKey = '';

    @property({ displayName: '是否Https' })
    isSSL: boolean = false;

    @property({ type: PlatformDefine, displayName: '平台', tooltip: '请选择平台' })
    platform: number = 0;


    start() {
        // 创建持久根节点
        // @ts-ignore
        director.addPersistRootNode(this.node);
        this.phoenix = PhoenixIns;
    }

    protected onDestroy(): void {
        this.phoenix?.onDestroy();   
    }

    bindAvatarModel(avatarModel: IModelData) {
        this.phoenix!.bindAvatarModel(avatarModel);
    }

    public InitPhoeix(){
        this.phoenix!.init(this.platform, this.host, this.port, this.isSSL, this.secretKey);
        this.phoenix!.initMessage();
        this.phoenix!.setphoenixRoot(this);
        this.queryServerInfo();
        this.phoenix!.InitPhoenix();
    }

    public PhoenixVersion(){
        return this.phoenix?.PhoenixVersion();
    }

    public SetRequestTimeOut(time: number){
        this.phoenix?.setRequestTimeOut(time);
    }
    
    async loginCallBack(re: boolean, reCode: number) {
        if (re) {
            if(!this.checkLoginHasAvatar()){
                let reBackCode = await this.createAvatar(this.phoenix?.getAvatarModel()?.SerializeData());
                reCode = reBackCode.valueOf();
                if (reBackCode == 0) {
                    console.log("创建角色成功");
                } else {
                    console.log("创建角色失败=>" + reBackCode);
                    this.node.emit(PhoenixEventDefine.PHOENIX_LOGIN_FAIL, reCode);
                    return;
                }
            }else{
                let reBackCode = await this.getAvatar();
                reCode = reBackCode.valueOf();
                if (reBackCode == 0) {
                    console.log("获取角色成功");
                } else {
                    console.log("创建角色失败=>" + reBackCode);
                    this.node.emit(PhoenixEventDefine.PHOENIX_LOGIN_FAIL, reCode);
                    return;
                }
            }
            this.node.emit(PhoenixEventDefine.PHOENIX_LOGIN_SUCCESS, reCode);
        } else {
            this.node.emit(PhoenixEventDefine.PHOENIX_LOGIN_FAIL, reCode);
        }
    }

    registerEvent(type: string | NodeEventType, callback: __private.__types_globals__AnyFunction, target?: unknown, useCapture?: any) {
        this.node.on(type, callback, target, useCapture);
    }

    @PhoenixInit
    platformLogin(account:string, pass:string) {
        this.phoenix!.initAccount(account, pass);
        // 第三方平台,要先去获取openid
        if (this.phoenix!.isThirdPlatform()) {
            this.phoenix!.thirdPlatformLogin((re:any) => {
                if (re == 0) {
                    this.gameStartLogin();
                } else {
                    this.loginCallBack(false, re);
                }
            });
        } else {
            this.gameStartLogin();
        }
    }

    checkLoginHasAvatar(): boolean {
        return this.phoenix!.checkLoginHasAvatar();
    }

    clear() {
        this.phoenix!.clear();
    }

    /**
     * 异步创建角色方法
     * @param avatarData 角色数据，泛型T，具体类型根据使用场景确定
     * @param name 角色名称，默认为空字符串
     * @returns 返回一个Promise，该Promise解析为一个数字类型，表示操作的结果代码
     */
    @PhoenixInit
    async createAvatar(avatarData: any, name: string = ''): Promise<Number> {
        let reCode: Number = 0; // 初始化返回代码为0
        // 调用phoenix的createAvatar方法创建角色，然后打印并赋值返回代码
        await this.phoenix!.createAvatar(avatarData, name).then((code) => {
            console.log(code);
            reCode = code;
        });
        return reCode; // 返回操作结果代码
    }

    @PhoenixInit
    async getAvatar(): Promise<Number> {
        let reCode: Number = 0;
        await this.phoenix!.getAvatar().then((code) => {
            console.log(code);
            reCode = code;
        });
        return reCode;
    }

    @PhoenixInit
    async updateAvatar(): Promise<Number> {
        let reCode: Number = 0;
        await this.phoenix!.updateAvtar().then((code) => {
            console.log(code);
            reCode = code;
        });
        return reCode;
    }

    @PhoenixInit
    async useCDKey(code:string): Promise<{code:number, extra:string}> {
        let reCode: {code:number, extra:string} = {code:-1, extra:''} ;
        await this.phoenix!.useCDKey(code).then((backData) => {
            console.log(code);
            reCode = backData;
        });
        return reCode;
    }

    @PhoenixInit
    async updateAccountToken(): Promise<Number> {
        if (!this.phoenix!.CheckIsInit()) {
            console.log("请先调用InitPhoeix方法初始化Phoenix");
            return -1;
        }
        let reCode: Number = 0;
        await this.phoenix!.updateAccountToken().then((code) => {
            console.log(code);
            reCode = code;
        });
        return reCode;
    }

    async updateThirdAccountToken(): Promise<Number> {
        let reCode: Number = 0;
        await this.phoenix!.updateThirdAccountToken().then((code) => {
            console.log(code);
            reCode = code;
        });
        return reCode;
    }

    async alipayReportAction(actionCode: string, actionFinishChannel: string): Promise<Number> {
        let reCode: Number = 0;
        await this.phoenix!.alipayReportAction(actionCode, actionFinishChannel).then((code) => {
            console.log(code);
            reCode = code;
        });
        return reCode;
    }

    
    async bytejumpReportAction(actionCode: string, actionFinishChannel: string): Promise<Number> {
        let reCode: Number = 0;
        await this.phoenix!.bytejumpReportAction(actionCode, actionFinishChannel).then((code) => {
            console.log(code);
            reCode = code;
        });
        return reCode;
    }

    async bytejumpGetEcpm(cb: (data:any) => void): Promise<Number> {
        let reCode: Number = 0;
        await this.phoenix!.bytejumpGetEcpm(cb).then((code) => {
            console.log(code);
            reCode = code;
        });
        return reCode;
    }

    async kuaiShouReportAction(actionCode: string, actionFinishChannel: string, eventProps:Map<string, number>): Promise<Number> {
        let reCode: Number = 0;
        await this.phoenix!.kuaiShouReportAction(actionCode, actionFinishChannel, eventProps).then((code) => {
            console.log(code);
            reCode = code;
        });
        return reCode;
    }

    queryServerInfo() {
        this.phoenix!.queryServerInfo((code:any) => {
            console.log(code);
            if (code == 0) {
                this.node.emit(PhoenixEventDefine.PHOENIX_QUERY_SERVER_SUCCESS, code);
            } else {
                this.node.emit(PhoenixEventDefine.PHOENIX_QUERY_SERVER_FAIL, code);
            }
        });
    }

    queryConfigs(callback: (code: number, data:any)=>void){
        this.phoenix!.queryConfigs(callback);
    }

    updateServerTimer(){
        this.phoenix!.updateServerTimer();
    }
    /**
     * 去中心服务器查询账号及账号所在服务器信息
     */
    gameStartLogin() {
        let reCode: Number = 0;
        this.phoenix!.queryAccount((code:any) => {
            console.log(code);
            reCode = code;
            if (reCode == 0) {
                this.node.emit(PhoenixEventDefine.PHOENIX_QUERY_CENTER_SUCCESS, reCode);
                // 先更新选服
                this.phoenix!.updateCenter((code:any) => {
                    if (code == 0) {
                        // 再执行登录
                        this.node.emit(PhoenixEventDefine.PHOENIX_CENTER_UPDATE_SUCCESS, code);
                        this.phoenix!.gameLogin();
                    } else {
                        this.node.emit(PhoenixEventDefine.PHOENIX_CENTER_UPDATE_FAIL, code);
                    }
                });
            } else {
                this.node.emit(PhoenixEventDefine.PHOENIX_QUERY_CENTER_FAIL, reCode);
            }
        });
    }

    
    /**
     * 更新订阅信息
     * @param subscribeType 订阅类型 number
     * @param delayTime  延迟时间(秒) number
     * @returns 
     */
    async updateSubscribeDelay(subscribeType:number, delayTime:number): Promise<Number>{
        let reCode: Number = 0;
        let sendDate = new Date(Date.now() + delayTime * 1000);
        let sendTime = dayjs(sendDate).format("YYYY-MM-DD HH:mm:ss");
        await this.phoenix!.updateSubscribe(subscribeType, sendTime).then((code) => {
            console.log(code);
            reCode = code;
        });
        return reCode;
    }

    /**
     * 更新版本订阅,这个订阅时间会被设置为10年之后,需要在版本更新后,后台操作修改推送时间
     * @returns 
     */
    async updateSubscribeVersion(): Promise<Number>{
        let reCode: Number = 0;
        await this.updateSubscribeDelay(2, 315360000).then((code) => {
            console.log(code);
            reCode = code;
        });
        return reCode;
    }    
    
    /**
     * 更新订阅信息
     * @param subscribeType 订阅类型 number
     * @param sendTime  发送时间  string 格式 : yyyy-MM-dd HH:mm:ss
     * @returns 
     */
    async updateSubscribe(subscribeType:number, sendTime:string): Promise<Number>{
        let reCode: Number = 0;
        await this.phoenix!.updateSubscribe(subscribeType, sendTime).then((code) => {
            console.log(code);
            reCode = code;
        });
        return reCode;
    }

    async serverCallThirdPlatform(thirdUrl: string, data: object): Promise<Number> {
        let reCode: Number = 0;
        await this.phoenix!.serverCallThirdPlatform(thirdUrl, data).then((code) => {
            console.log(code);
            reCode = code;
        });
        if (reCode == 0) {
            this.node.emit(PhoenixEventDefine.PHOENIX_THIRD_CALL_SUCCESS, this.phoenix!.getThirdCallBackData());
        } else {
            this.node.emit(PhoenixEventDefine.PHOENIX_THIRD_CALL_FAIL, reCode);
        }
        return reCode;
    }

    /**
     * 创建商品订单
     * @param goods 商品ID(配置表主键) string
     * @param goodsContent 商品内容(发放信息配置) string
     * @param goodsPrice  商品价格 number
     * @param extraData 扩展信息 jsonString
     */
    async orderCreate(goods:string, goodsContent:string, goodsPrice:number, extraData:string, callBack:(code:any, data:any) => void){
        let orderInput = new OrderCreateInput();
        orderInput.goods = goods;
        orderInput.goodsContent = goodsContent;
        orderInput.goodsPrice = goodsPrice;
        orderInput.data = extraData;
        let res = await this.phoenix!.orderCreate(orderInput);
        callBack(res.code, res.data);
    }

    /**
     * 查询订单
     * export enum OrderStatus {
            Normal = 0,     // 未付款
            Payed,      // 已付款
            Finished,   // 已发货
        }
     * @param status 订单状态 -1 就是查询所有
     * @param callBack 
     */
    async orderQuery(status:number, callBack:(code:any, data:any) => void){
        let orderInput = new OrderQueryInput();
        orderInput.status = status;
        let res = await this.phoenix!.orderQuery(orderInput);
        callBack(res.code, res.data);
    }

    /**
     * 通知服务器订单已发放
     * @param order 订单号 string
     * @param callBack 
     */
    async orderSend(order:string, callBack:(code:any, data:any) => void){
        let orderInput = new OrderSendInput();
        orderInput.order = order;
        let res = await this.phoenix!.orderSend(orderInput);
        callBack(res.code, res.data);
    }

    /**
     * 通知服务器订单已完成支付
     * @param order 订单号 string
     * @param callBack 
     */
    async orderPayed(order:string, callBack:(code:any, data:any) => void){
        let orderInput = new OrderPayedInput();
        orderInput.order = order;
        let res = await this.phoenix!.orderPayed(orderInput);
        callBack(res.code, res.data);
    }

    public selectServerZone(zone: number) {
        return this.phoenix!.selectServerBySid(zone);
    }

    public selectServer(index?: number) {
        return this.phoenix!.selectServer(index);
    }

    public getAccountIns(): Account | null {
        return this.phoenix!.getAccountIns();
    }

    public getAvatarIns(): Avatar| null  {
        return this.phoenix!.getAvatarIns();
    }

    public getServerTimer(): number {
        return this.phoenix!.getServerTimer();
    }

    public setServerTimer(serverTimer: number): void {
        this.phoenix!.setServerTimer(serverTimer);
    }

    public getSelectServerZone(): number {
        return this.phoenix!.getSelectServerZone();
    }

    public loginGameServer(){
        this.phoenix!.loginGameServer();
    }

    public sendGamePacket(packet: Packet){
        this.phoenix!.sendGamePacket(packet!);
    }

    public sendBundle() {
        this.phoenix!.sendBundle();
    }

    public update(dt:any){
        messageManager.processMessage();
    }

    public setAvatarModuleData(moduleId:number, data:any){
        this.phoenix!.setAvatarModuleData(moduleId, data);
    }

    public getAvatarModuleData(moduleId:number){
        return this.phoenix!.getAvatarModuleData(moduleId);
    }

    public async updateAvatarModule(moduleId:number){
        return await this.phoenix!.updateAvatarModuleToServer(moduleId);
    }

    public async getAvatarModule(moduleId:number){
        return await this.phoenix!.getAvatarModuleFromServer(moduleId);
    }

    public async getThirdAvatarModule(moduleId:number, avatarId:number, callBack:(data:AvatarModuleResponse)=>void)
    {
        return await this.phoenix!.getThirdAvatarModuleFromServer(moduleId, avatarId, callBack);
    }

    public async storeSet(key:string, value:string, length:number = 20){
        return await this.phoenix!.avatarSoreSet(key, value, length);
    }

    public async storeGet(key:string, callBack:(data:any)=>void){
        return await this.phoenix!.avatarSoreGet(key, callBack);
    }

    public async storeDel(key:string, value:string[]){
        return await this.phoenix!.avatarSoreDel(key, value);
    }

    public async avatarWxQrcode(scene:string, version:string, width:number, callBack:(data:any)=>{}){
        return await this.phoenix!.avatarWxQrcode(scene, version, width, callBack);
    }

    public async avatarShotLink(pageUrl:string, callBack:(data:any)=>{}){
        return await this.phoenix!.avatarShortLink(pageUrl, callBack);
    }

    public async getAvatarData(callBack:(data:any)=>{}){
        return await this.phoenix!.getAvatarData(callBack);
    }

    /**
     * 抽取卡片
     * @param cardType 卡片类型
     * @param chooseTimes 抽取次数
     * @param chooseOld 已经抽取次数
     * @param choose_records 抽取记录
     * @param callBack 
     */
    public async cardChoose(cardType:number, chooseTimes:number, chooseOld:number, choose_records:number[], callBack:(code:any, data:any) => void){
        let input = new CardChooseInput();
        input.card_Type = cardType;
        input.choose_times = chooseTimes;
        input.choose_old = chooseOld;
        input.choose_records = JSON.stringify(choose_records);
        let res = await this.phoenix!.cardChoose(input);
        callBack(res.code, res.data);
    }


    public copyAccountNameToClipBoard(){
        let accountName = this.phoenix!.getAccountIns()!.getAccountName();
        this.copyToClipBoard(accountName);
    }

    public copyToClipBoard(str:any) :boolean {
        if (sys.isNative) {
        //原生自己实现
        } else if (sys.isBrowser) {
            var textarea = document.createElement("textarea");
            textarea.textContent = str;
            document.body.appendChild(textarea);
            textarea.readOnly = true;
            textarea.select();
            textarea.setSelectionRange(0, textarea.textContent!.length);
            try {
                const flag = document.execCommand('copy');
                document.body.removeChild(textarea);
                if(flag){
                    console.log("已经复制到剪贴板");
                    return true;
                }else{
                    console.log("复制到剪贴板失败");
                    return false;
                }
            } catch (err) {
                console.log("复制到剪贴板失败");
                return false;
            }
        }
        return false;
    }

    public setAppId(appId:string){
        this.phoenix!.setAppId(appId);
    }
}
